﻿using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Shapes;

namespace DotNetUI.Controls.Shapes
{
    /// <summary>
    /// 环状
    /// </summary>
    public class Ring:Shape
    {
        protected override Geometry DefiningGeometry => this.Data;
        /// <summary>
        /// 设置值
        /// </summary>
        public Geometry Data { get => this.GetValue<Geometry>(DataProperty); set => this.SetValue(DataProperty, value); }
        /// <summary>
        /// 数据属性
        /// </summary>
        public static readonly DependencyProperty DataProperty = DependencyProperty.Register(nameof(Data), typeof(Geometry), typeof(Ring), new PropertyMetadata(Geometry.Empty, (s, e) =>
        {
            if (s is Ring arc && e.NewValue?.ToString() != e.OldValue?.ToString())
            {
                arc.InvalidateVisual();
            }
        }));
        /// <summary>
        /// 位置信息，大小信息
        /// </summary>
        public Rect Rect { get => this.GetValue<Rect>(RectProperty); set => SetValue(RectProperty, value); }
        /// <summary>
        /// 环状的宽度
        /// </summary>
        public double RingWidth { get=>this.GetValue<double>(RingWidthProperty); set=>SetValue(RingWidthProperty,value); }
        public static readonly  DependencyProperty RingWidthProperty = DependencyProperty.Register(nameof(RingWidth), typeof(double), typeof(Ring), new PropertyMetadata(0.0, OnAngleChangedCallBack));
        /// <summary>
        /// 边框
        /// </summary>
        public static readonly DependencyProperty RectProperty = DependencyProperty.Register(nameof(Rect), typeof(Rect), typeof(Ring), new PropertyMetadata(Rect.Empty, OnAngleChangedCallBack));
        /// <summary>
        /// 起始角度
        /// </summary>
        public double StartAngle { get => this.GetValue<double>(StartAngleProperty); set => SetValue(StartAngleProperty, value); }
        /// <summary>
        /// 开始角度
        /// </summary>
        public static readonly DependencyProperty StartAngleProperty = DependencyProperty.Register(nameof(StartAngle), typeof(double), typeof(Ring), new PropertyMetadata(0.0D, OnAngleChangedCallBack));
        /// <summary>
        /// 结束角度
        /// </summary>
        public static readonly DependencyProperty EndAngleProperty = DependencyProperty.Register(nameof(EndAngle), typeof(double), typeof(Ring), new PropertyMetadata(0.0D, OnAngleChangedCallBack));
        /// <summary>
        /// 结束角度
        /// </summary>
        public double EndAngle { get => this.GetValue<double>(EndAngleProperty); set => SetValue(EndAngleProperty, value); }
        /// <summary>
        /// 角度修改回调
        /// </summary>
        /// <param name="dependencyObject"></param>
        /// <param name="dependencyPropertyChangedEventArgs"></param>
        protected static void OnAngleChangedCallBack(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
        {
            if (dependencyObject is Ring arc)
            {
                arc.OnAngleChanged();
            }
        }
        protected virtual void OnAngleChanged()
        {
            if (this.Rect.Width > 0 && this.Rect.Height > 0 && this.StartAngle != EndAngle)
            {
                var data = GetLine(this.Rect, StartAngle, EndAngle);
                Data = data;
            }
            else
            {
                Data = Geometry.Empty;
            }
        }
        /// <summary>
        /// 获取线条
        /// </summary>
        /// <param name="outter"></param>
        /// <param name="startAngle"></param>
        /// <param name="endAngle"></param>
        /// <returns></returns>
        protected Geometry GetLine(Rect outter, double startAngle, double endAngle) 
        {

            double outerx = outter.Width / 2;
            double outery = outter.Height / 2;
            var wi = RingWidth / 2;

            Rect inner = new Rect(outter.X + wi, outter.Y + wi, outter.Width - RingWidth, outter.Height - RingWidth);
            double innerx = inner.Width / 2;
            double innery = inner.Height / 2;
            if (Math.Abs(startAngle - endAngle) % 360 == 0)
            {
                CombinedGeometry pathGeometry = new CombinedGeometry();
                pathGeometry.GeometryCombineMode = GeometryCombineMode.Xor;
                pathGeometry.Geometry1 = new EllipseGeometry { Center=new Point {X= outter.X + outerx, Y= outter.Y + outery },RadiusX= outerx,RadiusY= outery };
                pathGeometry.Geometry2 = new EllipseGeometry { Center = new Point { X = outter.X + outerx, Y = outter.Y + outery },RadiusX= innerx ,RadiusY=innery};
                return pathGeometry;

            }
            else
            {

                PathGeometry pathGeometry = new PathGeometry();
                var figure=  GetPath(startAngle, endAngle,outter, outerx, outery, inner, innerx, innery);
                pathGeometry.Figures.Add(figure);
                return pathGeometry;
           }
        }

        private PathFigure GetPath(double startAngle, double endAngle, Rect outter, double outerx, double outery, Rect inner, double innerx, double innery)
        {
            var outterclockWise = endAngle > startAngle;
            var outtermajorArc = Math.Abs(startAngle - endAngle) % 360 >= 180;

            Point outterp1 = startAngle.GetPoint(outerx, outery);
            Point outterp2 = endAngle.GetPoint(outerx, outery);
            var outterstartPoint = new Point { X = outterp1.X + outerx + outter.X, Y = outterp1.Y + outery + outter.Y };
            var outterendPoint = new Point { X = outterp2.X + outerx + outter.X, Y = outterp2.Y + outery + outter.Y };
            var path = new PathFigure { StartPoint = outterstartPoint, IsClosed = true };

            path.Segments.Add(new ArcSegment { Size = new Size() { Height = outery, Width = outerx }, IsLargeArc = outtermajorArc, SweepDirection = outterclockWise ? SweepDirection.Clockwise : SweepDirection.Counterclockwise, Point = outterendPoint });

            Point innerp1 = startAngle.GetPoint(innerx, innery);
            Point innerp2 = endAngle.GetPoint(innerx, innery);

            var innerstartPoint = new Point { X = innerp1.X + innerx + inner.X, Y = innerp1.Y + innery + inner.Y };
            var innerendPoint = new Point { X = innerp2.X + innerx + inner.X, Y = innerp2.Y + innery + inner.Y };

            path.Segments.Add(new LineSegment {Point= innerendPoint });

            path.Segments.Add(new ArcSegment { Size = new Size() { Height = innery, Width = innerx }, IsLargeArc = outtermajorArc, SweepDirection = !outterclockWise ? SweepDirection.Clockwise : SweepDirection.Counterclockwise, Point = innerstartPoint });


            return path;
        }
    }
}
